﻿using System;
using NMock2.Internal;
using NMock2.Syntax;

namespace NMock2
{
	/// <summary>
	/// This class represents a stub.
	/// <para><span style="color:red;font-weight:bold;">This class is new to NMock3.</span></para>
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class Stub<T>
		where T : class
	{
		private readonly object _proxy;

		internal Stub(object proxy)
		{
			if (proxy == null)
				throw new ArgumentNullException("proxy");

			_proxy = proxy;
		}

		/// <summary>
		/// An object of type <typeparamref name="T" /> to be used whenever the Mocked object is needed.
		/// </summary>
		/// <remarks>
		/// This property provides access to the proxy that is mocking the actual type.  Use this property
		/// when a reference to an object that is of the mocked type is needed.
		/// </remarks>
		/// <example>
		/// This example shows how a presenter needs arguments of the right type during construction.  The
		/// <c>MockObject</c> property is used because the presenter can't be instantiated with a <see cref="Mock{T}"/>
		/// argument.
		/// <code>
		/// interface IView { ... }
		/// interface IModel { ... }
		/// 
		/// Stub&lt;IView&gt; view = factory.CreateStub&lt;IView&gt;();
		/// Stub&lt;IModel&gt; view = factory.CreateStub&lt;IModel&gt;();
		/// 
		/// Presenter p = new Presenter(view.MockObject, model.MockObject);
		/// </code>
		/// </example>
		public T MockObject
		{
			get
			{
				return (T)_proxy;
			}
		}

		/// <summary>
		/// A syntax property used to access members that specify expectations.
		/// </summary>
		public IMethodSyntax<T> Out
		{
			get
			{
				if (typeof(T).IsInterface)
					return new InterfaceExpectationBuilder<T>("Stub", Is.Anything, Is.Anything, _proxy){IsStub = true};
				else if (typeof(T).IsClass)
					return new ClassExpectationBuilder<T>("Stub", Is.Anything, Is.Anything, _proxy) { IsStub = true };

				throw new InvalidOperationException("The type mocked is not a class or interface.");
			}
		}
	}
}
